using AutoMapper;
using B.S.Medical.Api.Read.Application.Command.Register;
using B.S.Medical.Api.Read.DTOS;
using B.S.Medical.Domain.Department;
using B.S.Medical.Domain.Doctor;
using B.S.Medical.Domain.Medical;
using B.S.Medical.ErrorCode;
using B.S.Medical.Infrastructure.Interface;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace B.S.Medical.Api.Read.Application.Handler.Register
{
    /// <summary>
    /// 获取患者挂号队列信息命令处理程序
    /// </summary>
    public class GetPatientQueueCommandHandler : IRequestHandler<GetPatientQueueCommand, ApiResult<List<PatientQueueInfoDto>>>
    {
        private readonly IBaseRepository<RegisterModel> _registerRepository;
        private readonly IBaseRepository<PatientModel> _patientRepository;
        private readonly IBaseRepository<DoctorModel> _doctorRepository;
        private readonly IBaseRepository<ManageModel> _departmentRepository;
        private readonly ILogger<GetPatientQueueCommandHandler> _logger;
        private readonly IMapper _mapper;

        public GetPatientQueueCommandHandler(
            IBaseRepository<RegisterModel> registerRepository,
            IBaseRepository<PatientModel> patientRepository,
            IBaseRepository<DoctorModel> doctorRepository,
            IBaseRepository<ManageModel> departmentRepository,
            ILogger<GetPatientQueueCommandHandler> logger,
            IMapper mapper)
        {
            _registerRepository = registerRepository;
            _patientRepository = patientRepository;
            _doctorRepository = doctorRepository;
            _departmentRepository = departmentRepository;
            _logger = logger;
            _mapper = mapper;
        }

        public async Task<ApiResult<List<PatientQueueInfoDto>>> Handle(GetPatientQueueCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 1. 查询用户 ID 对应的所有未删除患者（可能多个）
                var patients = await _patientRepository.GetAll()
                    .Where(p => p.AccountId == request.PatientId && !p.IsDeleted)
                    .ToListAsync(cancellationToken);

                if (patients == null || patients.Count == 0)
                {
                    _logger.LogWarning($"未找到患者信息, 用户ID={request.PatientId}", request.PatientId);
                    var noPatientResult = new ApiResult<List<PatientQueueInfoDto>>();
                    noPatientResult.Code = ApiEnum.Fail;
                    noPatientResult.Msg = "未找到患者信息";
                    noPatientResult.Success = false;
                    return noPatientResult;
                }

                var resultList = new List<PatientQueueInfoDto>();

                // 2. 遍历每个患者，单独处理挂号队列
                foreach (var patient in patients)
                {
                    // 查询该患者的待就诊挂号记录
                    var register = await _registerRepository.GetAll()
                        .Where(r => r.PatientId == patient.Id
                               && r.Status == "待就诊"
                               && !r.IsDeleted
                               && r.AppointmentTime.Date == DateTime.Now.Date)
                        .OrderByDescending(r => r.VisitDate)
                        .FirstOrDefaultAsync(cancellationToken);

                    if (register == null)
                    {
                        _logger.LogWarning($"患者 {patient.Id} 无待就诊预约信息, 用户ID={request.PatientId}", request.PatientId);
                        continue; // 无挂号记录则跳过，处理下一个患者
                    }

                    // 获取医生、科室信息（和原逻辑一致）
                    var doctor = await _doctorRepository.GetAll()
                        .Where(d => d.Id == register.DoctorId && !d.IsDeleted)
                        .FirstOrDefaultAsync(cancellationToken);

                    var department = doctor != null
                        ? await _departmentRepository.GetAll()
                            .Where(d => d.Id == doctor.DepartmentId && !d.IsDeleted)
                            .FirstOrDefaultAsync(cancellationToken)
                        : null;

                    // 查询同一医生、日期的所有待就诊患者（用于算队列）
                    var allQueueRegisters = await _registerRepository.GetAll()
                        .Where(r =>
                            r.DoctorId == register.DoctorId &&
                            r.VisitDate.Date == register.VisitDate.Date &&
                            r.Status == "待就诊" &&  // 仅保留【待就诊】患者
                            !r.IsDeleted
                        )
                        .OrderBy(r => r.registrationId)
                        .ToListAsync(cancellationToken);

                    // 获取队列患者信息（和原逻辑一致）
                    var patientIds = allQueueRegisters.Select(r => r.PatientId).Distinct().ToList();
                    var allPatients = await _patientRepository.GetAll()
                        .Where(p => patientIds.Contains(p.Id) && !p.IsDeleted)
                        .ToDictionaryAsync(p => p.Id, cancellationToken);

                    var myQueueRegister = allQueueRegisters
                        .FirstOrDefault(r => r.PatientId == patient.Id);
                    var myQueuePosition = myQueueRegister != null
                        ? allQueueRegisters.IndexOf(myQueueRegister)
                        : -1;
                    
                    // 计算前面还有几位患者
                    int patientsAhead = myQueuePosition > 0 ? myQueuePosition : 0;
                    
                    var otherQueueRegisters = allQueueRegisters
                        .Where(r => r.PatientId != patient.Id)
                        .ToList();

                    // 5. 构建他人队列 DTO
                    var otherPatients = new List<QueuePatientDto>();
                    for (int i = 0; i < otherQueueRegisters.Count; i++)
                    {
                        var queueRegister = otherQueueRegisters[i];
                        if (allPatients.TryGetValue(queueRegister.PatientId, out var queuePatient))
                        {
                            int actualQueuePosition = allQueueRegisters.IndexOf(queueRegister);
                            otherPatients.Add(new QueuePatientDto
                            {
                                PatientId = queuePatient.Id,
                                PatientName = queuePatient.Name,
                                RegisterId = queueRegister.Id,
                                SerialNumber = queueRegister.slot_number,
                                QueuePosition = actualQueuePosition // 使用实际队列位置
                            });
                        }
                    }

                    // 6. 构建单个患者的队列信息
                    var result = new PatientQueueInfoDto
                    {
                        PatientId = patient.Id,
                        PatientName = patient.Name,
                        RegisterId = register.Id,
                        DepartmentName = department?.DepartmentName ?? "未知科室",
                        DoctorName = doctor?.DoctorName ?? "未知医生",
                        SerialNumber = register.slot_number,
                        RegisterStatus = register.Status,
                        MyQueuePosition = myQueuePosition >= 0 ? myQueuePosition : 0,
                        PatientsAhead = patientsAhead, // 添加前面还有几位患者的信息
                        OtherPatients = otherPatients
                    };

                    resultList.Add(result);
                }

                // 3. 返回最终结果（包含所有患者的队列信息）
                var successResult = new ApiResult<List<PatientQueueInfoDto>>();
                successResult.Code = ApiEnum.Success;
                successResult.Msg = "获取患者挂号队列信息成功";
                successResult.Data = resultList;
                successResult.Success = true; // 确保语义一致
                return successResult;

            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"获取患者挂号队列信息异常，用户ID={request.PatientId}", request.PatientId);
                var errorResult = new ApiResult<List<PatientQueueInfoDto>>();
                errorResult.Code = ApiEnum.Error;
                errorResult.Msg = "获取患者挂号队列信息异常：" + ex.Message;
                errorResult.Success = false; // 明确设置失败状态
                return errorResult;
            }
        }
    }
} 